#pragma once

#include <cstdint>
#include <stdbool.h>
#include <stdint.h>

#include "luster_log.hh"
#include "luster_ownership.hh"
#include "luster_vec.hh"

namespace luster {

class Slice;

struct StringBuffer {
	// 保证为空或者以 '\0' 结束
	Vec<char> chars_;
};

static inline uintptr_t stringbuf_len(StringBuffer const *sbuf) {
	if (sbuf->chars_.len == 0)
		return 0;
	return sbuf->chars_.len - 1;
}

static inline char const *stringbuf_get(StringBuffer const *sbuf) {
	if (sbuf->chars_.len == 0)
		return "";
	return sbuf->chars_.data;
}

static inline char *stringbuf_mut(StringBuffer *sbuf) {
	if (sbuf->chars_.len == 0) {
		*vec_append_zero(&sbuf->chars_) = 0;
	}
	return sbuf->chars_.data;
}

static inline Logger operator<<(Logger logger, StringBuffer const &buf) {
	return logger << stringbuf_get(&buf);
}

void stringbuf_append_char(StringBuffer *buf, char c);
void stringbuf_append_cstring(StringBuffer *buf, char const *cstring);
void stringbuf_append_usize(StringBuffer *buf, uintptr_t x);
void stringbuf_append_slice(StringBuffer *buf, Slice slice);

static inline void stringbuf_ensure_end(StringBuffer *buf) {
	if (buf->chars_.len == 0)
		*vec_append_zero(&buf->chars_) = 0;
}

static inline void stringbuf_clear(StringBuffer *buf) {
	vec_clear(&buf->chars_);
}

luster_DROP(StringBuffer, buf) {
	stringbuf_clear(buf);
}

/* 以 '\0' 结尾的字符序列。它的长度是从开头到 '\0'（不包含）的字符数。 */
struct CString {
	Char const *start{};
};

static inline bool operator==(CString const &lhs, CString const &rhs) {
	return strcmp(lhs.start, rhs.start) == 0;
}

static inline Logger operator<<(Logger logger, CString const &cstring) {
	logger << cstring.start;
	return logger;
}

struct Slice {
	char const *data{};
	uintptr_t len{};
};

static inline Logger operator<<(Logger logger, Slice const &slice) {
	fwrite(slice.data, slice.len, 1, stderr);
	return logger;
}

bool slice_eq(Slice const *slice, char const *cstring);

static inline void stringbuf_append_stringbuf(
	StringBuffer *buf, StringBuffer const &that) {
	if (that.chars_.len <= 1)
		return;
	stringbuf_append_slice(
		buf, Slice{that.chars_.data, that.chars_.len - 1});
}

static inline bool operator==(Slice const &lhs, char c) {
	return lhs.len == 1 && lhs.data[0] == c;
}

static inline bool operator==(Slice const &lhs, char const *cstring) {
	return slice_eq(&lhs, cstring);
}

template <typename T>
static inline bool operator!=(Slice const &lhs, T const &rhs) {
	return !(lhs == rhs);
}

} // namespace luster
